home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / misc / gs261src.zip / gscie.c < prev    next >
C/C++ Source or Header  |  1993-05-18  |  15KB  |  432 lines

  1. /* Copyright (C) 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gscie.c */
  20. /* CIE color rendering for Ghostscript */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gxrefct.h"            /* early for gscie.h */
  24. #include "gxcolor.h"            /* early for gscolor2.h */
  25. #include "gscspace.h"
  26. #include "gscolor2.h"            /* for gs_set/currentcolorrendering */
  27. #include "gscie.h"
  28. #include "gxarith.h"
  29. #include "gxdevice.h"            /* for gs_color_index */
  30. #include "gzcolor.h"
  31. #include "gzstate.h"
  32.  
  33. /* Forward references */
  34. private void near cie_mult3(P3(const gs_vector3 *, const gs_matrix3 *, gs_vector3 *));
  35. private void near cie_matrix_mult3(P3(const gs_matrix3 *, const gs_matrix3 *, gs_matrix3 *));
  36. private void near cie_invert3(P2(const gs_matrix3 *, gs_matrix3 *));
  37. private void near cie_restrict3(P3(const gs_vector3 *, const gs_range3 *, gs_vector3 *));
  38. private void near cie_lookup3(P3(const gs_vector3 *, const gx_cie_cache *, gs_vector3 *));
  39. private void near cie_matrix_init(P1(gs_matrix3 *));
  40.  
  41. #define lookup(vin, pcache, vout)\
  42.   if ( (pcache)->is_identity ) vout = (vin);\
  43.   else vout = (pcache)->values[(int)(((vin) - (pcache)->base) * (pcache)->factor)]
  44.  
  45. #define restrict(vin, range, vout)\
  46.   if ( (vin) < (range).rmin ) vout = (range).rmin;\
  47.   else if ( (vin) > (range).rmax ) vout = (range).rmax;\
  48.   else vout = (vin)
  49.  
  50. /* ------ Default values for CIE dictionary elements ------ */
  51.  
  52. /* Default transformation procedures. */
  53.  
  54. private int
  55. a_identity(const float *in, const gs_cie_a *pcie, float *out)
  56. {    *out = *in;
  57.     return 0;
  58. }
  59. private int
  60. abc_identity(const gs_vector3 *in, const gs_cie_abc *pcie, gs_vector3 *out)
  61. {    *out = *in;
  62.     return 0;
  63. }
  64. private int
  65. common_identity(const gs_vector3 *in, const gs_cie_common *pcie, gs_vector3 *out)
  66. {    *out = *in;
  67.     return 0;
  68. }
  69. private int
  70. render_identity(const gs_vector3 *in, const gs_cie_render *pcie, gs_vector3 *out)
  71. {    *out = *in;
  72.     return 0;
  73. }
  74. private int
  75. tpqr_identity(const gs_vector3 *in, const gs_cie_wbsd *pwbsd, const gs_cie_render *pcie, gs_vector3 *out)
  76. {    *out = *in;
  77.     return 0;
  78. }
  79. private int
  80. render_table_identity(const byte *in, int m, const gs_cie_render *pcie, float *out)
  81. {    int j;
  82.     for ( j = 0; j < m; j++ ) out[j] = in[j] / 255.0;
  83.     return 0;
  84. }
  85.  
  86. /* Default vectors and matrices. */
  87.  
  88. const gs_range3 Range3_default = { {0,1}, {0,1}, {0,1} };
  89. const gs_cie_abc_proc3 DecodeABC_default = abc_identity;
  90. const gs_cie_common_proc3 DecodeLMN_default = common_identity;
  91. const gs_matrix3 Matrix3_default = { {1,0,0}, {0,1,0}, {0,0,1}, 1 };
  92. const gs_range RangeA_default = {0,1};
  93. const gs_cie_a_proc DecodeA_default = a_identity;
  94. const gs_vector3 MatrixA_default = { 1, 1, 1 };
  95. const gs_vector3 BlackPoint_default = { 0, 0, 0 };
  96. const gs_cie_render_proc3 Encode_default = render_identity;
  97. const gs_cie_transform_proc3 TransformPQR_default = tpqr_identity;
  98. const gs_cie_render_table_proc RenderTableT_default = render_table_identity;
  99.  
  100. /* setcolorrendering */
  101. int
  102. gs_setcolorrendering(gs_state *pgs, gs_cie_render *pcie)
  103. {    int code = gs_cie_render_init(pcie);
  104.     if ( code < 0 ) return code;
  105.     rc_assign(pgs->cie_render, pcie, pgs->memory_procs,
  106.           "gs_setcolorrendering");
  107.     /* Initialize the joint caches, if needed, */
  108.     /* by re-installing the color space. */
  109.     (*pgs->color_space->type->install_cspace)(pgs->color_space, pgs);
  110.     return gx_remap_color(pgs);
  111. }
  112.  
  113. /* currentcolorrendering */
  114. const gs_cie_render *
  115. gs_currentcolorrendering(const gs_state *pgs)
  116. {    return pgs->cie_render;
  117. }
  118.  
  119. /* Get the joint caches, to avoid having to import gzstate.h */
  120. gx_cie_joint_caches *
  121. gx_currentciecaches(gs_state *pgs)
  122. {    return pgs->cie_joint_caches;
  123. }
  124.  
  125. /* ------ Complete a rendering structure ------ */
  126.  
  127. int
  128. gs_cie_render_init(gs_cie_render *pcie)
  129. {    gs_matrix3 PQR_inverse;
  130.     cie_matrix_init(&pcie->MatrixLMN);
  131.     cie_matrix_init(&pcie->MatrixABC);
  132.     cie_matrix_init(&pcie->MatrixPQR);
  133.     cie_invert3(&pcie->MatrixPQR, &PQR_inverse);
  134.     cie_matrix_mult3(&PQR_inverse, &pcie->MatrixLMN, &pcie->MatrixPQR_inverse_LMN);
  135.     cie_mult3(&pcie->points.WhitePoint, &pcie->MatrixPQR, &pcie->wdpqr);
  136.     cie_mult3(&pcie->points.BlackPoint, &pcie->MatrixPQR, &pcie->bdpqr);
  137.     /****** FINISH ******/
  138.     return 0;
  139. }
  140.  
  141. /* ------ Fill in the joint cache ------ */
  142.  
  143. int
  144. gx_cie_joint_caches_init(gx_cie_joint_caches *pjc,
  145.   const gs_cie_common *pcie, const gs_cie_render *pcier)
  146. {    pjc->points_sd.ws.xyz = pcie->points.WhitePoint;
  147.     cie_mult3(&pjc->points_sd.ws.xyz, &pcier->MatrixPQR, &pjc->points_sd.ws.pqr);
  148.     pjc->points_sd.bs.xyz = pcie->points.BlackPoint;
  149.     cie_mult3(&pjc->points_sd.bs.xyz, &pcier->MatrixPQR, &pjc->points_sd.bs.pqr);
  150.     pjc->points_sd.wd.xyz = pcier->points.WhitePoint;
  151.     pjc->points_sd.wd.pqr = pcier->wdpqr;
  152.     pjc->points_sd.bd.xyz = pcier->points.BlackPoint;
  153.     pjc->points_sd.bd.pqr = pcier->bdpqr;
  154.     /****** FINISH ******/
  155.     return 0;
  156. }
  157.  
  158. /* ------ Remap (render) a CIE color (using the caches). ------ */
  159.  
  160. private int near cie_remap_finish(P4(const gs_vector3 *,
  161.   const gs_cie_common *, gx_device_color *, gs_state *));
  162.  
  163. /* Render a CIEBasedABC color. */
  164. int
  165. gx_remap_CIEBasedABC(const gs_client_color *pc, const gs_color_space *pcs,
  166.   gx_device_color *pdc, gs_state *pgs)
  167. {    const gs_cie_abc *pcie = pcs->params.abc;
  168.     gs_vector3 abc, lmn;
  169.     cie_restrict3((const gs_vector3 *)&pc->paint.values[0], &pcie->RangeABC, &abc);
  170.         /* (*pcie->DecodeABC)(&abc, pcie, &abc); */
  171.     cie_lookup3(&abc, &pcie->caches.DecodeABC[0], &abc);
  172.     cie_mult3(&abc, &pcie->MatrixABC, &lmn);
  173.     return cie_remap_finish(&lmn, &pcie->common, pdc, pgs);
  174. }
  175.  
  176. /* Render a CIEBasedA color. */
  177. int
  178. gx_remap_CIEBasedA(const gs_client_color *pc, const gs_color_space *pcs,
  179.   gx_device_color *pdc, gs_state *pgs)
  180. {    const gs_cie_a *pcie = pcs->params.a;
  181.     const gx_cie_cache *pcache = &pcie->caches.DecodeA;
  182.     float a;
  183.     gs_vector3 lmn;
  184.     restrict(pc->paint.values[0], pcie->RangeA, a);
  185.         /* (*pcie->DecodeA)(&a, pcie, &a); */
  186.     lookup(a, pcache, a);
  187.     lmn.u = a * pcie->MatrixA.u;
  188.     lmn.v = a * pcie->MatrixA.v;
  189.     lmn.w = a * pcie->MatrixA.w;
  190.     return cie_remap_finish(&lmn, &pcie->common, pdc, pgs);
  191. }
  192.  
  193. /* Common rendering code. */
  194. private int near
  195. cie_remap_finish(const gs_vector3 *plmn, const gs_cie_common *pcommon,
  196.   gx_device_color *pdc, gs_state *pgs)
  197. {    const gs_cie_render *pcie = pgs->cie_render;
  198.     const byte **table;
  199.     gs_vector3 abc, lmn, xyz, pqr;
  200.     gs_client_color cc;
  201.     gs_color_space cs;
  202.  
  203.         /* Finish decoding. */
  204.  
  205.     cie_restrict3(plmn, &pcommon->RangeLMN, &lmn);
  206.         /* (*pcommon->DecodeLMN)(&lmn, pcommon, &lmn); */
  207.     cie_lookup3(&lmn, &pcommon->caches.DecodeLMN[0], &lmn);
  208.     cie_mult3(&lmn, &pcommon->MatrixLMN, &xyz);
  209.  
  210.         /* Render. */
  211.  
  212.     if ( pcie == 0 )        /* default rendering */
  213.     {    abc = xyz;
  214.         table = 0;
  215.     }
  216.     else
  217.     {    const gx_cie_joint_caches *pjc = pgs->cie_joint_caches;
  218.         cie_mult3(&xyz, &pcie->MatrixPQR, &pqr);
  219.         cie_restrict3(&pqr, &pcie->RangePQR, &pqr);
  220.             /* (*pcie->TransformPQR)(&pqr, &pjc->points_sd, pcie, &pqr); */
  221.         cie_lookup3(&pqr, &pjc->TransformPQR[0], &pqr);
  222.         cie_mult3(&pqr, &pcie->MatrixPQR_inverse_LMN, &lmn);
  223.             /* (*pcie->EncodeLMN)(&lmn, pcie, &lmn); */
  224.         cie_lookup3(&lmn, &pcie->caches.EncodeLMN[0], &lmn);
  225.         cie_restrict3(&lmn, &pcie->RangeLMN, &lmn);
  226.         cie_mult3(&lmn, &pcie->MatrixABC, &abc);
  227.             /* (*pcie->EncodeABC)(&abc, pcie, &abc); */
  228.         cie_lookup3(&abc, &pcie->caches.EncodeABC[0], &abc);
  229.         cie_restrict3(&abc, &pcie->RangeABC, &abc);
  230.         table = pcie->RenderTable.table;
  231.     }
  232.     if ( table == 0 )
  233.     {    /* No further transformation */
  234.         cc.paint.values[0] = abc.u;
  235.         cc.paint.values[1] = abc.v;
  236.         cc.paint.values[2] = abc.w;
  237.         cs.type = &gs_color_space_type_DeviceRGB;
  238.     }
  239.     else
  240.     {    /* Use the RenderTable. */
  241.         int m = pcie->RenderTable.m;
  242. #define ri(s,n)\
  243.   (int)((abc.s - pcie->RangeABC.s.rmin) * (pcie->RenderTable.n - 1) /\
  244.     (pcie->RangeABC.s.rmax - pcie->RangeABC.s.rmin) + 0.5)
  245.         int ia = ri(u, NA);
  246.         int ib = ri(v, NB);
  247.         int ic = ri(w, NC);
  248.         const byte *prtc =
  249.           table[ia] + m * (ib * pcie->RenderTable.NC + ic);
  250.             /* (*pcie->RenderTable.T)(prtc, m, pcie, &cc.paint.values[0]); */
  251. #define shift_in(b) gx_cie_byte_to_cache_index(b)
  252. #define rtc(i) (pcie->caches.RenderTableT[i])
  253.         cc.paint.values[0] = rtc(0).values[shift_in(prtc[0])];
  254.         cc.paint.values[1] = rtc(1).values[shift_in(prtc[1])];
  255.         cc.paint.values[2] = rtc(2).values[shift_in(prtc[2])];
  256.         if ( m == 3 )
  257.         {    cs.type = &gs_color_space_type_DeviceRGB;
  258.         }
  259.         else
  260.         {    cc.paint.values[3] = rtc(3).values[shift_in(prtc[3])];
  261.             cs.type = &gs_color_space_type_DeviceCMYK;
  262.         }
  263. #undef rtc
  264. #undef shift_in
  265.     }
  266.     return (*cs.type->remap_color)(&cc, &cs, pdc, pgs);
  267. }
  268.  
  269. /* ------ Adjust reference counts for a CIE color space ------ */
  270.  
  271. int
  272. gx_adjust_CIEBasedABC(gs_color_space *pcs, gs_state *pgs, int delta)
  273. {    rc_adjust(pcs->params.abc, delta, pgs->memory_procs,
  274.           "gx_adjust_CIEBasedABC");
  275.     return 0;
  276. }
  277.  
  278. int
  279. gx_adjust_CIEBasedA(gs_color_space *pcs, gs_state *pgs, int delta)
  280. {    rc_adjust(pcs->params.a, delta, pgs->memory_procs,
  281.           "gx_adjust_CIEBasedA");
  282.     return 0;
  283. }
  284.  
  285. /* ------ Install a CIE color space ------ */
  286. /* These routines should load the cache, but they don't. */
  287.  
  288. int
  289. gx_install_CIEBasedABC(gs_color_space *pcs, gs_state *pgs)
  290. {    gs_cie_abc *pcie = pcs->params.abc;
  291.     cie_matrix_init(&pcie->common.MatrixLMN);
  292.     cie_matrix_init(&pcie->MatrixABC);
  293.     if ( pgs->cie_render == 0 )
  294.         return 0;
  295.     rc_unshare(pgs->cie_joint_caches, gx_cie_joint_caches,
  296.            pgs->memory_procs, return gs_error_VMerror,
  297.            "gx_install_CIEBasedABC");
  298.     return gx_cie_joint_caches_init(pgs->cie_joint_caches,
  299.         &pcie->common, pgs->cie_render);
  300. }
  301.  
  302. int
  303. gx_install_CIEBasedA(gs_color_space *pcs, gs_state *pgs)
  304. {    gs_cie_a *pcie = pcs->params.a;
  305.     cie_matrix_init(&pcie->common.MatrixLMN);
  306.     if ( pgs->cie_render == 0 )
  307.         return 0;
  308.     rc_unshare(pgs->cie_joint_caches, gx_cie_joint_caches,
  309.            pgs->memory_procs, return gs_error_VMerror,
  310.            "gx_install_CIEBasedA");
  311.     return gx_cie_joint_caches_init(pgs->cie_joint_caches,
  312.         &pcie->common, pgs->cie_render);
  313. }
  314.  
  315. /* ------ Utilities ------ */
  316.  
  317. #define if_debug_vector3(str, vec)\
  318.   if_debug4('c', "%s[%g %g %g]\n", str, vec->u, vec->v, vec->w)
  319. #define if_debug_matrix3(str, mat)\
  320.   if_debug10('c', "%s[%g %g %g / %g %g %g / %g %g %g]\n", str,\
  321.     mat->cu.u, mat->cu.v, mat->cu.w, mat->cv.u, mat->cv.v, mat->cv.w,\
  322.     mat->cw.u, mat->cw.v, mat->cw.w)
  323.  
  324. /* Multiply a vector by a matrix. */
  325. /* Optimizing this routine is the justification for is_identity! */
  326. private void near
  327. cie_mult3(const gs_vector3 *in, register const gs_matrix3 *mat, gs_vector3 *out)
  328. {    if_debug_vector3("[c]mult", in);
  329.     if_debug_matrix3("      *", mat);
  330.     if ( mat->is_identity )
  331.         *out = *in;
  332.     else
  333.     {    float u = in->u, v = in->v, w = in->w;
  334.         out->u = (u * mat->cu.u) + (v * mat->cu.v) + (w * mat->cu.w);
  335.         out->v = (u * mat->cv.u) + (v * mat->cv.v) + (w * mat->cv.w);
  336.         out->w = (u * mat->cw.u) + (v * mat->cw.v) + (w * mat->cw.w);
  337.     }
  338.     if_debug_vector3("      =", out);
  339. }
  340.  
  341. /* Multiply two matrices.  We assume the result is not an alias for */
  342. /* either of the operands. */
  343. private void near
  344. cie_matrix_mult3(const gs_matrix3 *ma, const gs_matrix3 *mb, gs_matrix3 *mc)
  345. {    gs_vector3 row_in, row_out;
  346.     if_debug_matrix3("[c]matrix_mult", ma);
  347.     if_debug_matrix3("             *", mb);
  348. #define mult_row(e)\
  349.   row_in.u = ma->cu.e, row_in.v = ma->cv.e, row_in.w = ma->cw.e;\
  350.   cie_mult3(&row_in, mb, &row_out);\
  351.   mc->cu.e = row_out.u, mc->cv.e = row_out.v, mc->cw.e = row_out.w
  352.     mult_row(u);
  353.     mult_row(v);
  354.     mult_row(w);
  355. #undef mult_row
  356.     cie_matrix_init(mc);
  357.     if_debug_matrix3("             =", mc);
  358. }
  359.  
  360. /* Invert a matrix. */
  361. /* The output must not be an alias for the input. */
  362. private void near
  363. cie_invert3(register const gs_matrix3 *in, register gs_matrix3 *out)
  364. {    /* This is a brute force algorithm; maybe there are better. */
  365.     /* We label the array elements */
  366.     /*   [ A B C ]   */
  367.     /*   [ D E F ]   */
  368.     /*   [ G H I ]   */
  369. #define A cu.u
  370. #define B cv.u
  371. #define C cw.u
  372. #define D cu.v
  373. #define E cv.v
  374. #define F cw.v
  375. #define G cu.w
  376. #define H cv.w
  377. #define I cw.w
  378.     double coA = in->E * in->I - in->F * in->H; 
  379.     double coB = in->F * in->G - in->D * in->I; 
  380.     double coC = in->D * in->H - in->E * in->G;
  381.     double det = in->A * coA + in->B * coB + in->C * coC;
  382.     if_debug_matrix3("[c]invert", in);
  383.     out->A = coA / det;
  384.     out->D = coB / det;
  385.     out->G = coC / det;
  386.     out->B = (in->C * in->H - in->B * in->I) / det;
  387.     out->E = (in->A * in->I - in->C * in->G) / det;
  388.     out->H = (in->B * in->G - in->A * in->H) / det;
  389.     out->C = (in->B * in->F - in->C * in->E) / det;
  390.     out->F = (in->C * in->D - in->A * in->F) / det;
  391.     out->I = (in->A * in->E - in->B * in->D) / det;
  392.     if_debug_matrix3("        =", out);
  393. #undef A
  394. #undef B
  395. #undef C
  396. #undef D
  397. #undef E
  398. #undef F
  399. #undef G
  400. #undef H
  401. #undef I
  402.     out->is_identity = in->is_identity;
  403. }
  404.  
  405. /* Force values within bounds. */
  406. private void near
  407. cie_restrict3(const gs_vector3 *in, const gs_range3 *range, gs_vector3 *out)
  408. {    float temp;
  409.     temp = in->u; restrict(temp, range->u, out->u);
  410.     temp = in->v; restrict(temp, range->v, out->v);
  411.     temp = in->w; restrict(temp, range->w, out->w);
  412. }
  413.  
  414. private void near
  415. cie_lookup3(const gs_vector3 *in, const gx_cie_cache *pc /*[3]*/, gs_vector3 *out)
  416. {    if_debug4('c', "[c]lookup 0x%lx [%g %g %g]\n", (ulong)pc,
  417.           in->u, in->v, in->w);
  418.     lookup(in->u, pc, out->u); pc++;
  419.     lookup(in->v, pc, out->v); pc++;
  420.     lookup(in->w, pc, out->w);
  421.     if_debug_vector3("        =", out);
  422. }
  423.  
  424. /* Set the is_identity flag that accelerates multiplication. */
  425. private void near
  426. cie_matrix_init(register gs_matrix3 *mat)
  427. {    mat->is_identity =
  428.         mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
  429.         mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
  430.         mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
  431. }
  432.